/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  pinyin.h
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2015/12/22
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#pragma once
#include <map>

#include "../container/CHashMap.h"
#include "../core.h"
#include "../pointer/scoped_pointer.h"
#include "../strings/simple_array.h"
#include "../strings/string_convert.h"

namespace qb {
namespace base {
namespace pinyin {
struct HanziInfo;
enum { PINYIN_MAX_BUFLENGTH = 4096 };
}  // namespace pinyin
class S_CORE_EXPORT SpellBufBuilderImpl {
  int m_count;   // 有多少个拼音
  int m_length;  // 总共占有字符长度
  int m_capcity;
  wchar_t* m_buffer;  // 缓冲区
 public:
  SpellBufBuilderImpl(wchar_t* buf, int capcity);
  void Reset();
  void AddStart(wchar_t c);
  void AddString(const wchar_t* str, int len);
  void AddString(wchar_t str);
  const wchar_t* GetBuf() const { return m_buffer; }
  wchar_t* GetBuf() { return m_buffer; }
  int GetLength() const { return m_length; }
  int GetCapcity() const { return m_capcity; }
};

//--------------------------------------------------------------------------
// 在指定缓冲区中增加汉字拼音字符串
//--------------------------------------------------------------------------
template <int N>
class S_CORE_EXPORT SpellBufBuilder : public SpellBufBuilderImpl {
  wchar_t m_real_buffer[N];  // 缓冲区
 public:
  SpellBufBuilder() : SpellBufBuilderImpl(m_real_buffer, N) {}
};
class SpellMatch;
class S_CORE_EXPORT SpellManager {
 public:
  enum {
    MAX_SPELL_LEN = 10,  // 拼音字符串的最大长度
    MAX_HANZI_LEN = 4,   //
    MAX_SPELL_COUNT = 8  // 多音字的拼音最大个数
  };
  typedef struct {
    wchar_t data[MAX_SPELL_LEN];
  } tSpell;
  struct tHanzi {
    wchar_t code;
    // unsigned char data[MAX_HANZI_LEN];
    bool operator==(const tHanzi& hz) const { return code == hz.code; }
  };
  class tHanziHasher {
   public:
    unsigned int operator()(const tHanzi& hz) const {
      return (unsigned int)hz.code;
    }
  };
  class WCharHasher {
   public:
    unsigned int operator()(const wchar_t& hz) const {
      return (unsigned int)hz;
    }
  };
  typedef SFixedArray<int, MAX_SPELL_COUNT> tSpellIds;
  struct S_CORE_EXPORT SpellInfo {
    char tone;    // 1,2,3,4,5
    char len;     //
    tSpell name;  //
  };
  class SpellContext {
    typedef std::map<wchar_t, int> WCharIntMap;
    wchar_t m_code;        // 当前多音字
    WCharIntMap m_prefix;  // 前后相关的汉字
    WCharIntMap m_post;    // 前后相关的汉字
   public:
    SpellContext(wchar_t code) : m_code(code) {}
    void AddPrefix(wchar_t prefix, int index) {
      m_prefix.insert(WCharIntMap::value_type(prefix, index));
    }
    void AddPost(wchar_t post, int index) {
      m_post.insert(WCharIntMap::value_type(post, index));
    }
    bool GetSpellByPrefix(wchar_t prefix, int& index) {
      WCharIntMap::iterator it = m_prefix.find(prefix);
      if (it != m_prefix.end()) {
        index = it->second;
        return true;
      }
      return false;
    }
    bool GetSpellByPost(wchar_t post, int& index) {
      WCharIntMap::iterator it = m_post.find(post);
      if (it != m_post.end()) {
        index = it->second;
        return true;
      }
      return false;
    }
  };
  typedef CHashMap<wchar_t, SpellContext*, WCharHasher> SpellContextMap;
  typedef CHashMap<tHanzi, tSpellIds, tHanziHasher> HanziSpellMap;

 private:
  SimpleArray<SpellInfo>* m_spells;
  HanziSpellMap* m_spellid_map;
  SpellContextMap* m_prefixmap;
  unsigned char m_link_char;
  SpellBufBuilder<pinyin::PINYIN_MAX_BUFLENGTH> m_all_builder;
  SpellBufBuilder<pinyin::PINYIN_MAX_BUFLENGTH> m_short_builder;
  SpellMatch* m_spell_matcher;
  bool m_ignore_tone;
  CConvertFast m_convert;
  bool m_use_context;
  bool m_spell_capital;

 public:
  SpellManager();
  ~SpellManager();
  static int UnitTest();

  void SetUseContext(bool useContext) { m_use_context = useContext; }
  void LoadDict(const BaseString& fullDictFile);
  void LoadDict(const wchar_t* utf8Array, int size);
  void LoadDefaultDict();
  bool ExportDict(const BaseString& fullDictFile);

  int GetLastMatchPos() const;

  /*

          text
          tlen
          key
          klen
          full
          checkcn
  */
  bool IsMatchPinyin(const wchar_t* text, int tlen, const wchar_t* key,
                     int klen, bool full, bool checkcn);
  bool IsAlignMatchPinyin(const wchar_t* text, int tlen, const wchar_t* key,
                          int klen);

  bool GetAllSpellForString(const wstring& szStr, wstring& spell,
                            wstring& shortSpell);

  void GetPinyin(const wchar_t* buffer, wstring& sJianpin, wstring& sQuanpin);

  bool GetSpell(const wchar_t* text, int tlen, wchar_t* fullspell, int& flen,
                wchar_t* shortspell, int& slen);

  /*
          找出str中的多音字汉字,将其逐个追加到polyCharacters中
  */
  void GetPolySpell(const wstring& str, wstring& polyCharacters);

  /*
          找出汉字code的所有拼音,以逗号分割
  */
  int GetSpellString(wchar_t code, wstring& spell);
  int GetSpellStringWithContext(wchar_t code, wchar_t prev, wchar_t next,
                                wstring& spell);

  void Dump();

  /*
          根据前后汉字,计算汉字code的所有可能的拼音,将其放在ids中
          code:指定的汉字
          ids:获取汉字的所有拼音信息
          full:指定是需要汉字的拼音的全部英文字母,还是需要拼音的第一个英文字符
          prev:文本串中前一个汉字,用于根据多音字修正信息m_prefixmap过滤掉不用的拼音
          next:文本串中后一个汉字,用于根据多音字修正信息m_prefixmap过滤掉不用的拼音
  */
  bool GetSpellIdEx(wchar_t code, tSpellIds& ids, bool full, wchar_t prev,
                    wchar_t next);

  /*
          获取指定汉字的所有拼音信息的索引
          code:指定的汉字
          ids:返回的该汉字的所有拼音的索引
  */
  bool GetSpellId(wchar_t code, tSpellIds& ids);

  /*
          根据拼音索引获取拼音信息
  */
  const SpellInfo& GetSpellInfo(int id) const { return m_spells->at(id); }

 protected:
  int GetSpellIdByName(const tSpellIds& ids, const wchar_t* spell, int len);

  int SplitIntoHanziArray(const wchar_t* wstr, pinyin::HanziInfo* parray,
                          int capcity);
  void AddSpellLine(const char* linestr, int len, int i, bool isutf8);

  void AddPrefixLine(const wchar_t* line, int len = 0);
  void AddPrefixLineImpl(const wchar_t* line, int len = 0);
  void AddDefaultPrefixLines();
};

class S_CORE_EXPORT Spell {
 public:
  static void Parse(const wchar_t* buffer, int len, wchar_t* quanbuf,
                    int& quanlen, wchar_t* jianbuf, int& jianlen);
  static void ParseEx(const unsigned short* buffer, int len,
                      unsigned short* quanbuf, int& quanlen,
                      unsigned short* jianbuf, int& jianlen);
  static bool IsAlignMatchPinyin(const unsigned short* text, int tlen,
                                 const unsigned short* key, int klen);
  static bool IsMatchPinyin(const wchar_t* text, int tlen, const wchar_t* key,
                            int klen, bool full, bool checkcn);
};
}  // namespace base
}  // namespace qb
